﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using System;
using webapi.DTO;

using webapi.Helper;
using webapi.Model;

namespace webapi.Controllers
{
    [ApiController]
    [Route("[controller]")]
    [Authorize]
    public class OrderController : ControllerBase
    {
        private readonly ILogger<OrderController> _logger;

        private DbContextHelper _dbContextHelper;

        private PriceCalculateHelper _priceCalculateHelper;

        private FileHelper _fileHelper;

        public enum StatusEnum
        {
            UnPaid,
            Undelivered,
            Delivered,
            Completed, //灰色
            Processing,
            Returned, //灰色
            Deleted  //灰色
        }

        public OrderController(ILogger<OrderController> logger, DbContextHelper dbContextHelper)
        {
            _logger = logger;
            _dbContextHelper = dbContextHelper;
            _priceCalculateHelper = new PriceCalculateHelper();
            _fileHelper = new FileHelper();
        }

        /// <summary>
        /// 获取订单列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("GetOrderList")]
        [Authorize]
        public GetOrderListOutput GetOrderList([FromBody] GetOrderListInput input)
        {
            var user = HttpContext.User.Claims;
            var userGuid = user.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            List<OrderAllModel> orderList;

            List<Order> orders = new List<Order>();
            int listCount = 0;
            if (!string.IsNullOrWhiteSpace(input.filter) && input.filter != "-1")
            {
                listCount = _dbContextHelper.OrderAllModel.Where(p => p.DELETE_DATE == null).Where(b => b.USER_GUID == userGuid && b.ORDER_STATUS_CODE == input.filter).Count();
                orderList = _dbContextHelper.OrderAllModel.Where(p => p.DELETE_DATE == null).Where(b => b.USER_GUID == userGuid && b.ORDER_STATUS_CODE == input.filter).OrderByDescending(p => p.CREATE_DATETIME).Skip(input.pageSize * (input.pageNum - 1)).Take(input.pageSize).ToList();
            }
            else
            {
                listCount = _dbContextHelper.OrderAllModel.Where(p => p.DELETE_DATE == null).Where(b => b.USER_GUID == userGuid).Count();
                orderList = _dbContextHelper.OrderAllModel.Where(p => p.DELETE_DATE == null).Where(b => b.USER_GUID == userGuid).OrderByDescending(p => p.CREATE_DATETIME).Skip(input.pageSize * (input.pageNum - 1)).Take(input.pageSize).ToList();
            }
            foreach (var order in orderList)
            {
                var orderInfo = _dbContextHelper.OrderInfoModel.Where(p => p.DELETE_DATE == null && p.GUID == order.ORDER_INFO_GUID).FirstOrDefault();
                var product = _dbContextHelper.ProductInfo.Where(p => p.DELETE_DATE == null && p.PRODUCT_ID == order.PRODUCT_ID).FirstOrDefault();

                if (product != null && orderInfo != null)
                {
                    orders.Add(new Order()
                    {
                        product_id = order.PRODUCT_ID.ToString(),
                        product_img = product.PRODUCT_MEDIA1,
                        product_name = product.PRODUCT_NAME,
                        order_id = order.ORDER_ID,
                        order_num = order.ORDER_NUM,
                        total_price = orderInfo.ORDER_TOTAL_PRICE,
                        order_status_code = order.ORDER_STATUS_CODE,
                        order_status_desc = order.ORDER_STATUS_DESC,
                        create_date = order.CREATE_DATETIME.ToString(),
                        tracking_number = orderInfo.TRACKING_NUMBER,
                        //tracking_img = orderInfo.ORDER_MEDIA1,
                        deliver_date = orderInfo.DELIVERY_DATE == null ? "" : orderInfo.DELIVERY_DATE.ToString(),
                        return_tracking_number = orderInfo.RETURN_TRACKING_NUMBER,
                        //return_tracking_img = orderInfo.ORDER_MEDIA2,
                        return_reason = orderInfo.RETURN_REASON,
                        return_date = orderInfo.RETURN_DATE == null ? "" : orderInfo.RETURN_DATE.ToString()
                    });
                }
            }
            return new GetOrderListOutput()
            {
                data = orders,
                page_count = listCount % input.pageSize == 0 ? (int)(listCount / input.pageSize) : (int)(listCount / input.pageSize) + 1,
                error_code = "2000",
                status = "200",
                msg = ""
            };
        }

        [HttpPost("CreateOrder")]
        [Authorize]
        public CreateOrderOutput CreateOrder(CreateOrderInput inputList)
        {
            var user = HttpContext.User.Claims;
            var userGuid = user.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            // 无限库存，不考虑库存数量。 
            //bool hasProductSoldOut = false;
            double orderTotalPrice = 0;
            List<String> OrderIdList = new List<string>();
            foreach (var input in inputList.order_list)
            {
                OrderAllModel orderAll = new OrderAllModel();
                OrderInfoModel orderInfo = new OrderInfoModel();
                double totalPrice = 0;
                double productPrice = 0;
                double quantity = 0;
                string orderId = "";
                string orderInfoguid = Guid.NewGuid().ToString();
                string orderAllguid = Guid.NewGuid().ToString();
                Random random = new Random();
                var productId = int.Parse(input.product_id);

                DateTimeOffset now = DateTimeOffset.Now;
                long timeStamp = now.ToUnixTimeSeconds();

                var product = _dbContextHelper.ProductInfo.Where(p => p.PRODUCT_ID == productId).FirstOrDefault();
                var userM = _dbContextHelper.UserInfo.Where(p => p.GUID == userGuid).FirstOrDefault();
                var cartProduct = _dbContextHelper.CartModel.Where(p => p.PRODUCT_ID == productId && p.USER_GUID == userGuid).FirstOrDefault();
                if (product != null && userM != null && !string.IsNullOrWhiteSpace(userGuid) && cartProduct != null)
                {
                    //if (decimal.Parse(product.PRODUCT_NUM) <= 0)
                    //{
                    //    hasProductSoldOut = true;
                    //    continue;
                    //}
                    //product.PRODUCT_NUM = (decimal.Parse(product.PRODUCT_NUM) - 1).ToString();

                    double.TryParse(product.PRODUCT_PRICE, out productPrice);
                    double.TryParse(input.quantity, out quantity);
                    totalPrice = _priceCalculateHelper.PriceCalculate(productPrice, quantity);
                    orderTotalPrice += totalPrice;
                    orderId = $"{timeStamp}{random.Next(1000, 10000)}";

                    orderAll.GUID = orderAllguid;
                    orderAll.ORDER_INFO_GUID = orderInfoguid;
                    orderAll.ORDER_NUM = input.quantity;
                    orderAll.CREATE_DATETIME = DateTime.Now;
                    orderAll.USER_GUID = userGuid;
                    orderAll.PRODUCT_ID = productId;
                    orderAll.ORDER_ID = orderId;
                    orderAll.ORDER_STATUS_CODE = "0";
                    orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.UnPaid) ?? "Unpaid";

                    orderInfo.GUID = orderInfoguid;
                    orderInfo.ORDER_ID = orderId;
                    orderInfo.PRODUCT_ID = productId;
                    orderInfo.ORDER_TOTAL_COUNT = input.quantity;
                    orderInfo.ORDER_TOTAL_PRICE = totalPrice.ToString();

                    var resOA = _dbContextHelper.OrderAllModel.Add(orderAll);
                    var resOI = _dbContextHelper.OrderInfoModel.Add(orderInfo);
                    OrderIdList.Add(orderId);
                    if (cartProduct != null)
                    {
                        _dbContextHelper.CartModel.Remove(cartProduct);
                    }
                    _dbContextHelper.SaveChanges();
                }
                else
                {
                    return new CreateOrderOutput()
                    {
                        error_code = "2001",
                        status = "200",
                        msg = "Create Order Failed."
                    };
                }
            }
            return new CreateOrderOutput()
            {
                total_price = orderTotalPrice.ToString(),
                order_ids = OrderIdList,
                error_code = "2000",
                status = "200",
                msg = "Create Order Succeed."
            };
        }

        [HttpPost("CreateSingleOrder")]
        [Authorize]
        public CreateOrderOutput CreateSingleOrder(CreateOrderInput inputList)
        {
            var user = HttpContext.User.Claims;
            var userGuid = user.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            //bool hasProductSoldOut = false;
            double orderTotalPrice = 0;
            List<String> OrderIdList = new List<string>();
            foreach (var input in inputList.order_list)
            {
                OrderAllModel orderAll = new OrderAllModel();
                OrderInfoModel orderInfo = new OrderInfoModel();
                double totalPrice = 0;
                double productPrice = 0;
                double quantity = 0;
                string orderId = "";
                string orderInfoguid = Guid.NewGuid().ToString();
                string orderAllguid = Guid.NewGuid().ToString();
                Random random = new Random();
                var productId = int.Parse(input.product_id);

                DateTimeOffset now = DateTimeOffset.Now;
                long timeStamp = now.ToUnixTimeSeconds();

                var product = _dbContextHelper.ProductInfo.Where(p => p.PRODUCT_ID == productId).FirstOrDefault();
                var userM = _dbContextHelper.UserInfo.Where(p => p.GUID == userGuid).FirstOrDefault();
                //var cartProduct = _dbContextHelper.CartModel.Where(p => p.PRODUCT_ID == productId && p.USER_GUID == userGuid).FirstOrDefault();
                if (product != null && userM != null && !string.IsNullOrWhiteSpace(userGuid))
                {
                    //if (decimal.Parse(product.PRODUCT_NUM) <= 0)
                    //{
                    //    hasProductSoldOut = true;
                    //    continue;
                    //}
                    //product.PRODUCT_NUM = (decimal.Parse(product.PRODUCT_NUM) - 1).ToString();

                    double.TryParse(product.PRODUCT_PRICE, out productPrice);
                    double.TryParse(input.quantity, out quantity);
                    totalPrice = _priceCalculateHelper.PriceCalculate(productPrice, quantity);
                    orderTotalPrice += totalPrice;
                    orderId = $"{timeStamp}{random.Next(1000, 10000)}";

                    orderAll.GUID = orderAllguid;
                    orderAll.ORDER_INFO_GUID = orderInfoguid;
                    orderAll.ORDER_NUM = input.quantity;
                    orderAll.CREATE_DATETIME = DateTime.Now;
                    orderAll.USER_GUID = userGuid;
                    orderAll.PRODUCT_ID = productId;
                    orderAll.ORDER_ID = orderId;
                    orderAll.ORDER_STATUS_CODE = "0";
                    orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.UnPaid) ?? "Unpaid";

                    orderInfo.GUID = orderInfoguid;
                    orderInfo.ORDER_ID = orderId;
                    orderInfo.PRODUCT_ID = productId;
                    orderInfo.ORDER_TOTAL_COUNT = input.quantity;
                    orderInfo.ORDER_TOTAL_PRICE = totalPrice.ToString();

                    var resOA = _dbContextHelper.OrderAllModel.Add(orderAll);
                    var resOI = _dbContextHelper.OrderInfoModel.Add(orderInfo);
                    OrderIdList.Add(orderId);
                    //if (cartProduct != null)
                    //{
                    //    _dbContextHelper.CartModel.Remove(cartProduct);
                    //}
                    _dbContextHelper.SaveChanges();
                }
                else
                {
                    return new CreateOrderOutput()
                    {
                        error_code = "2001",
                        status = "200",
                        msg = "Create Order Failed."
                    };
                }
            }
            return new CreateOrderOutput()
            {
                total_price = orderTotalPrice.ToString(),
                order_ids = OrderIdList,
                error_code = "2000",
                status = "200",
                msg = "Create Order Succeed."
            };
        }

        [HttpPost("SaveOrderReturnExpressInfo")]
        [Authorize]
        public OutputDTO SaveOrderReturnExpressInfo([FromBody] SaveOrderExpressInfoInput input)
        {
            var userClaim = HttpContext.User.Claims;
            var userGuid = userClaim.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            if (string.IsNullOrWhiteSpace(input.order_id))
            {
                return new OutputDTO()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "Save Express Info Failed."
                };
            }
            var oldExpressInfo = _dbContextHelper.OrderTrackingNumberModel.Where(p => p.DELETE_DATE == null && p.ORDER_ID == input.order_id && p.TRACKING_NUMBER_TYPE == "RETURN").ToList();
            foreach (var old in oldExpressInfo)
            {
                old.DELETE_DATE = DateTime.Now;
            }
            foreach (var item in input.express_info)
            {
                OrderTrackingNumberModel model = new OrderTrackingNumberModel();
                model.GUID = Guid.NewGuid().ToString();
                model.ORDER_ID = input.order_id;
                model.TRACKING_NUMBER_TYPE = "RETURN";
                model.TRACKING_NUMBER = item.tracking_number;
                model.EXPRESS_COMPANY = item.express_company;
                model.USER_GUID = userGuid;
                _dbContextHelper.OrderTrackingNumberModel.Add(model);
            }
            if (input.express_info.Count > 0)
            {
                var orderAll = _dbContextHelper.OrderAllModel.Where(p => p.ORDER_ID == input.order_id && p.USER_GUID == userGuid).FirstOrDefault();
                if (orderAll != null)
                {
                    if (orderAll.ORDER_STATUS_CODE != ((int)StatusEnum.Processing).ToString())
                    {
                        orderAll.ORDER_STATUS_CODE = ((int)StatusEnum.Processing).ToString();
                        orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.Processing) ?? "Processing";
                    }
                }
            }
            _dbContextHelper.SaveChanges();
            return new OutputDTO()
            {
                error_code = "2000",
                status = "200",
                msg = "Save Express Info Succeed."
            };
        }

        [HttpPost("GetOrderExpressInfo")]
        [Authorize]
        public GetOrderExpressInfoOutput GetOrderExpressInfo(GetOrderExpressInfoInput input)
        {
            var userClaim = HttpContext.User.Claims;
            var userGuid = userClaim.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            var userGroupId = userClaim.FirstOrDefault(c => c.Type == "UserGroupId")?.Value;
            if (string.IsNullOrWhiteSpace(input.order_id))
            {
                return new GetOrderExpressInfoOutput()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "Get Express Info Failed."
                };
            }
            var expressInfo = _dbContextHelper.OrderTrackingNumberModel.Where(p => p.DELETE_DATE == null && p.ORDER_ID == input.order_id && p.TRACKING_NUMBER_TYPE == "RETURN" && (userGroupId == "1" || p.USER_GUID == userGuid)).ToList();
            List<ExpressInfo> expressList = new List<ExpressInfo>();
            foreach (var item in expressInfo)
            {
                expressList.Add(new ExpressInfo()
                {
                    express_company = (item.EXPRESS_COMPANY != null) ? item.EXPRESS_COMPANY : "",
                    tracking_number = (item.TRACKING_NUMBER != null) ? item.TRACKING_NUMBER : ""
                });
            }

            return new GetOrderExpressInfoOutput()
            {
                express_info = expressList,
                error_code = "2000",
                status = "200",
                msg = "Get Express Info Succeed."
            };
        }

        [HttpPost("GetOrderDeliverExpressInfo")]
        [Authorize]
        public GetOrderExpressInfoOutput GetOrderDeliverExpressInfo(GetOrderExpressInfoInput input)
        {
            var userClaim = HttpContext.User.Claims;
            var userGuid = userClaim.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            if (string.IsNullOrWhiteSpace(input.order_id))
            {
                return new GetOrderExpressInfoOutput()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "Get Express Info Failed."
                };
            }
            var expressInfo = _dbContextHelper.OrderTrackingNumberModel.Where(p => p.DELETE_DATE == null && p.ORDER_ID == input.order_id && p.TRACKING_NUMBER_TYPE == "DELIVER" && p.USER_GUID == userGuid).ToList();
            List<ExpressInfo> expressList = new List<ExpressInfo>();
            foreach (var item in expressInfo)
            {
                expressList.Add(new ExpressInfo()
                {
                    express_company = (item.EXPRESS_COMPANY != null) ? item.EXPRESS_COMPANY : "",
                    tracking_number = (item.TRACKING_NUMBER != null) ? item.TRACKING_NUMBER : ""
                });
            }

            return new GetOrderExpressInfoOutput()
            {
                express_info = expressList,
                error_code = "2000",
                status = "200",
                msg = "Get Express Info Succeed."
            };
        }

        [HttpPost("EditOrderReturn")]
        [Authorize]
        public OutputDTO EditOrderReturn(EditOrderReturnInput input)
        {
            var userClaim = HttpContext.User.Claims;
            var userGuid = userClaim.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            var userGroupId = userClaim.FirstOrDefault(c => c.Type == "UserGroupId")?.Value;
            //string imagePath = null;

            //if (!string.IsNullOrWhiteSpace(input.return_image) && !string.IsNullOrWhiteSpace(input.order_id))
            //{
            //    _fileHelper.DownloadImageByBase64(input.return_image, "return" + input.order_id, "./FileServer/public/orders");
            //    imagePath = "orders/" + "return" + input.order_id + ".png";
            //}
            if ((!string.IsNullOrWhiteSpace(input.return_number) || !string.IsNullOrWhiteSpace(input.return_reason)) && !string.IsNullOrWhiteSpace(input.order_id))
            {
                var order = _dbContextHelper.OrderInfoModel.Where(p => p.ORDER_ID == input.order_id).FirstOrDefault();
                var orderAll = _dbContextHelper.OrderAllModel.Where(p => p.ORDER_ID == input.order_id && p.USER_GUID == userGuid).FirstOrDefault();
                if (order != null && orderAll != null)
                {
                    if (orderAll.ORDER_STATUS_CODE != ((int)StatusEnum.Delivered).ToString() && orderAll.ORDER_STATUS_CODE != ((int)StatusEnum.Processing).ToString())
                    {
                        return new OutputDTO()
                        {
                            error_code = "2001",
                            status = "200",
                            msg = "Update Order failed",
                        };
                    }
                    if (orderAll.ORDER_STATUS_CODE != ((int)StatusEnum.Processing).ToString())
                    {
                        orderAll.ORDER_STATUS_CODE = ((int)StatusEnum.Processing).ToString();
                        orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.Processing) ?? "Processing";
                    }
                    //if (imagePath != null)
                    //{
                    //    order.ORDER_MEDIA2 = imagePath;
                    //}
                    if (!string.IsNullOrWhiteSpace(input.return_number))
                    {
                        order.RETURN_TRACKING_NUMBER = input.return_number;
                    }
                    if (!string.IsNullOrWhiteSpace(input.return_reason))
                    {
                        order.RETURN_REASON = input.return_reason;
                    }
                    if (order.RETURN_DATE == null)
                    {
                        order.RETURN_DATE = DateTime.Now;
                    }
                    _dbContextHelper.SaveChanges();
                }
            }

            return new OutputDTO()
            {
                error_code = "2000",
                status = "200",
                msg = "Create Order Succeed."
            };
        }

        [HttpPost("ReceiveOrder")]
        [Authorize]
        public OutputDTO ReceiveOrder(ReceiveOrderInput input)
        {
            var userClaim = HttpContext.User.Claims;
            var userGuid = userClaim.FirstOrDefault(c => c.Type == "UserGuid")?.Value;
            var userGroupId = userClaim.FirstOrDefault(c => c.Type == "UserGroupId")?.Value;
            var orderAll = _dbContextHelper.OrderAllModel.Where(p => p.USER_GUID == userGuid && p.ORDER_ID == input.order_id && p.ORDER_STATUS_CODE == ((int)StatusEnum.Delivered).ToString()).FirstOrDefault();
            if (orderAll != null)
            {
                orderAll.ORDER_STATUS_CODE = ((int)StatusEnum.Completed).ToString();
                orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.Completed) ?? "Completed";
                _dbContextHelper.SaveChanges();
            }

            return new OutputDTO()
            {
                error_code = "2000",
                status = "200",
                msg = "Create Order Succeed."
            };
        }

        /// <summary>
        /// 订单支付完成ChangeOrderStatusInput
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost("ApproveOrder")]
        [Authorize]
        public OutputDTO ApproveOrder(ChangeOrderStatusInput input)
        {
            if (string.IsNullOrWhiteSpace(input.payment_order_id))
            {
                return new OutputDTO()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "payment_order_id Can not be null."
                };
            }
            NetHelper netHelper = new NetHelper();
            var token = netHelper.GetAccessTokenAsync();
            if (string.IsNullOrWhiteSpace(token))
            {
                return new OutputDTO()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "Approve Order error."
                };
            }
            var status = netHelper.GetOrderStatus(input.payment_order_id, token);
            if (string.IsNullOrWhiteSpace(status))
            {
                return new OutputDTO()
                {
                    error_code = "2001",
                    status = "200",
                    msg = "Approve Order error."
                };
            }
            if (status == "COMPLETED")
            {
                var oldOrder = _dbContextHelper.OrderInfoModel.Where(p => p.PAYMENT_ID == input.payment_order_id).FirstOrDefault();
                if (oldOrder != null)
                {
                    return new OutputDTO()
                    {
                        error_code = "2001",
                        status = "200",
                        msg = "Approve Order error."
                    };
                }
                foreach (var order_id in input.order_ids)
                {
                    var order = _dbContextHelper.OrderInfoModel.Where(p => p.ORDER_ID == order_id && p.PAYMENT_ID == null).FirstOrDefault();
                    var orderAll = _dbContextHelper.OrderAllModel.Where(p => p.ORDER_ID == order_id).FirstOrDefault();
                    if (order != null && orderAll != null)
                    {
                        order.PAYMENT_ID = input.payment_order_id;
                        orderAll.ORDER_STATUS_CODE = ((int)StatusEnum.Undelivered).ToString();
                        orderAll.ORDER_STATUS_DESC = Enum.GetName(typeof(StatusEnum), StatusEnum.Undelivered) ?? "Undelivered";
                        _dbContextHelper.SaveChanges();
                    }
                }

                return new OutputDTO()
                {
                    error_code = "2000",
                    status = "200",
                    msg = "Approve Order Succeed."
                };
            }
            return new OutputDTO()
            {
                error_code = "2000",
                status = "200",
                msg = "Approve Order Failed."
            };
        }

    }
}
